package com.kit.personalkit.tool;

import net.coobird.thumbnailator.Thumbnails;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;

public class ImageCompress {

    /**
     * 图片压缩算法：
     * 使用第三方库Thumbnails对原始图片进行压缩处理，
     * 图片压缩方法，接收一个字节数组（表示图片数据）、一个目标文件大小（单位为KB）和一个压缩精度。返回一个压缩后的字节数组。
     *
     */
    public byte[] compressPic(byte[] bytes, long desFileSize, double accuracy) throws IOException {
        long fileSize = bytes.length;

        // 如果图片大小小于等于指定文件大小，则直接返回原图
        if (fileSize <= desFileSize * 1024) {
            return bytes;
        }

        //把图片写进一个字节数组
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes));
        int desWidth = getDesDimension(bim.getWidth(), accuracy);
        int desHeight = getDesDimension(bim.getHeight(), accuracy);
        //将原始图片字节数据转换为InputStream对象。
        Thumbnails.of(new ByteArrayInputStream(bytes))
                //设置压缩后的图片宽度和高度。
                .size(desWidth, desHeight)
                //设置图片压缩的质量。
                .outputQuality(accuracy)
                //将压缩后的图片数据写入ByteArrayOutputStream对象。
                .toOutputStream(baos);
        byte[] outBytes = baos.toByteArray();
        long size = outBytes.length;

        // 如果不满足指定文件大小且压缩后的图片大小仍大于指定文件大小，则继续压缩
        while (size > desFileSize * 1024) {
            double ratio = Math.sqrt((double) (desFileSize * 1024) / size);
            outBytes = compressPic(outBytes, desFileSize, ratio);
            size = outBytes.length;
        }

        return outBytes;
    }

    //计算图片宽度和高度
    private int getDesDimension(int dimension, double accuracy) {
        return new BigDecimal(dimension).multiply(new BigDecimal(accuracy)).intValue();
    }

}
